﻿using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RedLockNet;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;
using StackExchange.Redis;

namespace AiQiuQuan.Sport.Core
{
    public static class RedLokcExtension
    {
        /// <summary>
        /// AddRedLock
        /// </summary>
        public static IServiceCollection AddRedLock(this IServiceCollection services, IConfiguration configuration)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            var redisCfg = configuration["RedisConnStr"];
            if (string.IsNullOrWhiteSpace(redisCfg))
            {
                throw new InvalidOperationException("RedisConnStr配置不存在");
            }

            var endPointCfg = new RedLockEndPointCfg { EndPointList = new List<string> { redisCfg } };
            services.AddSingleton<IDistributedLockFactory>(x =>
            {
                //日志
                var loggerFactory = x.GetRequiredService<ILoggerFactory>();

                //Redis节点
                var multiplexers = endPointCfg.EndPointList.Select(p => new RedLockMultiplexer(ConnectionMultiplexer.Connect(p))).ToList();

                return RedLockFactory.Create(multiplexers, loggerFactory);
            });

            return services;
        }

        /// <summary>
        /// UseRedLock
        /// </summary>
        public static IApplicationBuilder UseRedLock(this IApplicationBuilder app, IHostApplicationLifetime lifetime)
        {
            lifetime.ApplicationStopping.Register(() =>
            {
                var lockFactory = (IDisposable)app.ApplicationServices.GetRequiredService<IDistributedLockFactory>();
                lockFactory.Dispose();
            });

            return app;
        }
    }

    /// <summary>
    /// RedLockEndPointCfg
    /// </summary>
    internal class RedLockEndPointCfg
    {
        public List<string> EndPointList { get; set; }
    }
}
